package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstant;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 从阿里云iot平台同步某一个实例下面的所有的产品 并缓存到redis
     */
    @Override
    public void syncProductList() throws Exception {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setCurrentPage(1);
        request.setPageSize(200);

        QueryProductListResponse response = client.queryProductList(request);

        if(!response.getBody().success){
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }

        //获取到从iot平台查询到的所有的产品信息
        List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo =
                response.getBody().getData().getList().getProductInfo();

        List<ProductVo> voList = productInfo.stream().map(p -> {
            ProductVo vo = BeanUtil.toBean(p, ProductVo.class);
            return vo;
        }).collect(Collectors.toList());


        redisTemplate.opsForValue().set(CacheConstant.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(voList));
    }

    /**
     * 查询所有的产品
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        //1. 从redis中获取数据
        String json = redisTemplate.opsForValue().get(CacheConstant.ALL_PRODUCT_KEY);

        //2. 判断json字符串是否为空 如果为空则返回一个空的集合
        if(ObjectUtil.isEmpty(json)){
            return Collections.emptyList();
        }

        //3. 转换数据并返回
        List<ProductVo> productVoList = JSONUtil.toList(json, ProductVo.class);

        return productVoList;
    }

    /**
     * 新增设备
     *
     * @param deviceDto
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //1. 校验设备的名字是否使用过了 如果使用了 则抛出异常
        Integer count = deviceMapper.countName(deviceDto.getDeviceName());
        if(count > 0){
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }

        //2. 新增设备到iot平台
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse response = null;
        try {
             response = client.registerDevice(request);
        } catch (Exception e) {
            //3. 校验新增是否成功 如果失败 则抛出异常 - 主要针对的是网络异常 超时等异常情况
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //3. 校验新增是否成功 如果失败 则抛出异常 - 主要针对的是请求掉通了 但是阿里云因为各种原因注册失败了
        if(response == null || !response.getBody().success){
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //4. 判断设备的安装位置是否是老人 如果是 则需要把physical_location_type 设置为-1
        if(deviceDto.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())){
            deviceDto.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }

        //5. 到iot平台查询设备的详细信息
        QueryProductRequest req = new QueryProductRequest();
        req.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        req.setProductKey(deviceDto.getProductKey());
        try {
            QueryProductResponse productResponse = client.queryProduct(req);
            if(null != productResponse && productResponse.getBody().success){
                String productName = productResponse.getBody().getData().getProductName();
                //6. 分装pojo(deviceDto,设备的详细信息)
                Device device = BeanUtil.toBean(deviceDto, Device.class);
                device.setProductName(productName);
                device.setIotId(response.getBody().getData().getIotId());
                device.setHaveEntranceGuard(0);
                // 补充字段
                device.setCreateTime(LocalDateTime.now());
                device.setUpdateTime(LocalDateTime.now());
                device.setCreateBy(UserThreadLocal.get());

                //7. 调用mapper 插入设备数据
                deviceMapper.insert(device);
            }else{
                throw new RuntimeException();
            }

        } catch (Exception e) {
            e.printStackTrace();
            //8. 如果新增失败 则删除iot平台新增的设备
            DeleteDeviceRequest deleteReq = new DeleteDeviceRequest();
            deleteReq.setDeviceName(deviceDto.getDeviceName());
            deleteReq.setProductKey(deviceDto.getProductKey());
            deleteReq.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteReq.setIotId(response.getBody().getData().getIotId());

            try {
                DeleteDeviceResponse deviceResponse = client.deleteDevice(deleteReq);
            } catch (Exception ex) {
                //如果删除设备失败了 那么需要通过人工补偿的方式手工删除设备
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        }
    }

    /**
     * 根据条件分页查询设备数据
     *
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        Device device = BeanUtil.toBean(devicePageQueryDto, Device.class);

        Page<DeviceVo> page = deviceMapper.pageQueryDevice(device);

        return PageResponse.of(page, DeviceVo.class);
    }

    /**
     * 查询设备的详情数据
     *
     * @param request
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) throws Exception {
        //1. 通过iot平台查询平台中的设备详情数据
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response = client.queryDeviceDetail(request);
        if(response.getBody().success){
            //2. 通过iotid查询数据库中的设备数据
            Device device = deviceMapper.selectByIotId(request.getIotId());

            //3. 合并数据并返回
            DeviceVo deviceVo = BeanUtil.toBean(device, DeviceVo.class); //device[deviceName: sb001]
            BeanUtil.copyProperties(response.getBody().getData(), deviceVo, CopyOptions.create().ignoreNullValue());//getData[deviceName: null]

            return deviceVo;
        }

        return null;
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult queryDevicePropertyStatus(DeviceDto dto) throws Exception {

        QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();

        request.setDeviceName(dto.getDeviceName());
        request.setProductKey(dto.getProductKey());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryDevicePropertyStatusResponse response = client.queryDevicePropertyStatus(request);

        return ResponseResult.success(response.getBody().getData());
    }

    /**
     * 1.7 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult queryThingModelPublished(DeviceDto dto) throws Exception {
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();

        request.setProductKey(dto.getProductKey());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryThingModelPublishedResponse response = client.queryThingModelPublished(request);

        return ResponseResult.success(response.getBody().getData());
    }
}
